package compilador.analizadores;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import compilador.analizadorLexico.simbolos.SimboloLexico;

/**
 * Contiene las definiciones de los metodos que permitiran un analisis
 * lexico al lenguaje de programacion rrs.
 * 
 * @author Yurani Alejandra Salamanca Lotero
 * @author Nolberto Castellanos Rodriguez
 */
public class AnalizadorLexico {

	//************************************************************************
	// 								Atributos
	//************************************************************************

	/**
	 * Indice en el cual se indica en cual fila se encuentra el analizador
	 */
	private int filaActual;

	/**
	 * Indice en el cual se indica en cual columna se encuentra el analizador
	 */
	private int columnaActual;

	/**
	 * Posición del analizador en el momento acutal
	 */
	private int posicionActual;

	/**
	 * Caracter que se analiza actualmente
	 */
	private char caracterActual;

	/**
	 * Código que se analiza
	 */
	private String codigoFuente;
	
	/**
	 * Variable que nos indica cuando hemos llegado al fin del código
	 */
	private static char EOC = 0;

	/**
	 * Arraylist que contiene los tokens identificados
	 */
	private ArrayList<SimboloLexico> tablaSimbolos;
	
	/**
	 * Arraylist que contiene los errores identificados
	 */
	private ArrayList<SimboloLexico> tablaErrores;

	/**
	 * Arraylist que contiene las palabras reservadas
	 */
	private ArrayList<String> palabrasReservadas;
	
	/**
	 * Variable para la posición de backtrack
	 */
	private int backtrack;
	
	/**
	 * Ruta del archivo donde se encuentran las palabras reservadas
	 */
	private static String rutaPalabrasReservadas = "src/palabrasReservadas.txt";

	//************************************************************************
	// 								Constructor
	//************************************************************************
	
	/**
	 * Constructor por defecto del analizador lexico
	 */
	public AnalizadorLexico() {
		
		this.setBacktrack(0);
		this.palabrasReservadas = new ArrayList<String>();
		
		File f = new File(rutaPalabrasReservadas);
		BufferedReader entrada;
		try {
			
			entrada = new BufferedReader(new FileReader(f));
			String linea;
			
			while ((linea = entrada.readLine()) != null) 
				palabrasReservadas.add(linea);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	//************************************************************************
	// 								Métodos
	//************************************************************************
	
	/**
	 * Método que analiza el código fuente que se ingresa
	 * @param codigoFuente, codigo que se analiza
	 */
	public void analizar(String codigoFuente) {
		
		filaActual = columnaActual = 0; // Inicializamos el valor de la fila y la columna
		this.codigoFuente = codigoFuente+EOC; // Agregamos el fin de codigo
		posicionActual = 0; // Se asigna la posición inicial del indice

		// Se crean los arrays de los simbolos
		tablaSimbolos = new ArrayList<SimboloLexico>();
		tablaErrores = new ArrayList<SimboloLexico>();

		//Si el codigo fuente está vacio se asigna al caracter actual el fin de código
		if (codigoFuente.length() != EOC) 
			caracterActual = codigoFuente.charAt(posicionActual);
		else 
			caracterActual = EOC;

		// Se empieza a verificar cada token, al llegar al fin del código este se detiene
		while (caracterActual != EOC) {
			if (isPalabraReservada())
				continue;
			if (isComa())
				continue;
			if(isComentarioLinea())
				continue;
			if(isComentarioBloque())
				continue;
			if (isOperadorAditivo())
				continue;
			if (isOperadorMultiplicativo())
				continue;
			if(isRat())
				continue;
			if (isEntero())
				continue;
			if (isCadena())
				continue;
			if (isCaracter())
				continue;
			if (isIdentificadorAtributo())
				continue;
			if (isIdentificadorClase())
				continue;
			if (isIdentificadorMetodo())
				continue;
			if (isIdentificadorVariable())
				continue;
			if (isIdentificadorPaquete())
				continue;
			if (isSaltoLinea())
				continue;
			if (isTabulacion())
				continue;
			if (isEspacio())
				continue;
			if (isFinInstruccion())
				continue;
			if (isAsignacion())
				continue;
			if (isAgrupadorInicio())
				continue;
			if (isAgrupadorFin())
				continue;
			if (isOperadorRelacional())
				continue;
			if (isParentesisInicio())
				continue;
			if (isParentesisFin())
				continue;
			if (isIdentificadorNoValido())
				continue;
			
			//Si no se identifica el token este es enviado a la lista de errores con descripción desconocida
			almacenarError("" + caracterActual, "DESCONOCIDO", filaActual, columnaActual);
			siguienteCaracter(); // Se avanza al siguiente caracter
		}
	}

	/**
	 * Cambia el caracter actual por el que lo sigue en el código fuente
	 */
	public void siguienteCaracter() {
		if(codigoFuente.charAt(posicionActual+1)==EOC)
		{
			caracterActual=EOC;
		}
		else
		{   
			if(codigoFuente.charAt(posicionActual+1)=='\n')
			{
				filaActual++;
				columnaActual=-1;
			}
			else if(codigoFuente.charAt(posicionActual+1)=='\t')
			{
				columnaActual+=4;
			}
			else
			{
				columnaActual++;
			}
			posicionActual++;
			caracterActual=codigoFuente.charAt(posicionActual);
		}
	}
	
	/**
	 * Si se crea un lexema y este no corresponde a uno valido en la definición
	 * de ese token se regresará al comienzo del token para poder intentar en
	 * una nueva definición.
	 * 
	 * @param posParaBacktrack
	 */
	private void backtracking(int posParaBacktrack, int fil, int col)
	{
		this.posicionActual = posParaBacktrack;
		this.caracterActual = codigoFuente.charAt(posicionActual);
		this.filaActual = fil;
		this.columnaActual = col;
	}

	//----------------------------- Métodos que almacenan símbolos-------------------------
	
	/**
	 * Almacena el un token con toda su información en la tabla de símbolos
	 * 
	 * @param lexema Unidad de código
	 * @param token Tipo de la unidad de código
	 * @param filaInicial fila en la que se encuentra
	 * @param columnaInicial columna en la que se encuentra
	 */
	private void almacenarToken(String lexema, String token, int filaInicial, int columnaInicial) 
	{
		SimboloLexico aux = new SimboloLexico(lexema, token, filaInicial, columnaInicial);
		tablaSimbolos.add(aux);
	}

	/**
	 * Almacena el un token con toda su información en la tabla de errores
	 * 
	 * @param lexema Unidad de código
	 * @param token Tipo de la unidad de código
	 * @param filaInicial fila en la que se encuentra
	 * @param columnaInicial columna en la que se encuentra
	 */
	private void almacenarError(String lexema, String error, int filaInicial, int columnaInicial) 
	{
		SimboloLexico auxiliar = new SimboloLexico(lexema, error, filaInicial, columnaInicial);
		tablaErrores.add(auxiliar);
	}

	//------------------------------- Metodos de los token -----------------------------
	
	/**
	 * Indica si el caracter actual es un espacio en blanco.
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isEspacio() 
	{
		if (caracterActual == ' ') 
		{
			siguienteCaracter();
			return true;
		}
		return false;
	}
	
	/**
	 * Indica si el caracter actual es una tabulacion.
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isTabulacion() 
	{
		if (caracterActual == '\t') 
		{
			siguienteCaracter();
			return true;
		}
		return false;
	}

	/**
	 * Método que indica si el caracter actual es un salto de linea.
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isSaltoLinea() 
	{
		if (caracterActual == '\n') 
		{
			siguienteCaracter();
			return true;
		}
		
		return false;
	}

	/**
	 * Indica si el caracter actual es un fin de instrucción
	 * gramática: (;)
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isFinInstruccion() 
	{	
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == ';') 
		{
			almacenarToken(caracterActual + "", "Fin de Instrucción", fila, col);
			siguienteCaracter();
			return true;
		}
		return false;
	}

	/**
	 * Método que indica si el caracter actual es un símbolo de asignación
	 * @return true sí lo es, false de lo contrario.
	 * gramática: (:)
	 */
	public boolean isAsignacion() 
	{
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == ':')
		{
			almacenarToken(caracterActual + "", "Asignación", fila, col);
			siguienteCaracter();
			return true;
		}
		
		return false;
	}

	/**
	 * Método que indica si el caracter actual es un número entero
	 *  gramática: (D)^+
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isEntero()
	{	
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if (Character.isDigit(caracterActual)) 
		{
			lexema += caracterActual;
			siguienteCaracter();
			
			while (Character.isDigit(caracterActual) ) 
			{
				lexema += caracterActual;
				siguienteCaracter();
			}
			
			almacenarToken(lexema, "int", fila, col);
			return true;
		}
		
		return false;
	}
	
	/**
	 * Indica si el lexema actual es un número racional
	 * gramática: (D)^+(.)(D)^+
	 * 
	 * @return true si lo es, false de lo contrario. 
	 */
	public boolean isRat()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if (Character.isDigit(caracterActual)) 
		{	
			lexema += caracterActual;
			siguienteCaracter();
			
			while (Character.isDigit(caracterActual) ) 
			{
				lexema += caracterActual;
				siguienteCaracter();
			}
			
			if(caracterActual == '.')
			{	
				int contPunto = 1;
				int contDec = 0;
				int contCom = 0;
				
				lexema += caracterActual;
				siguienteCaracter();
				
				while (Character.isDigit(caracterActual) || caracterActual == '.'|| caracterActual == ',') 
				{	
					if(caracterActual == '.')
						contPunto++;
					
					if(caracterActual == ',')
						contCom++;
					
					if(Character.isDigit(caracterActual))
						contDec++;
						
					lexema += caracterActual;
					siguienteCaracter();
				}
				
				if(contPunto == 1 && contDec > 0  && contCom == 0)
					almacenarToken(lexema, "rat", fila, col);
				else
					almacenarError(lexema, "Error", fila, col);
			}
			else if(caracterActual == ',' )
			{	
				lexema += caracterActual;
				siguienteCaracter();
				
				while (Character.isDigit(caracterActual)|| caracterActual == '.' || caracterActual == ',' ) 
				{
					lexema += caracterActual;
					siguienteCaracter();
				}
				
				almacenarError(lexema, "Error", fila, col);
			}
			else
			{
				backtracking(backtrack, fila, col);
				return false;
			}
			
		return true;
	}
	else if(caracterActual == '.')
	{
		while (Character.isDigit(caracterActual) || caracterActual == '.' || caracterActual == ',' ) 
		{
				
			lexema += caracterActual;
			siguienteCaracter();
		}
		
		almacenarError(lexema, "Error", fila, col);
		
		return true;
	}
	else
		return false;
	}
	
	/**
	 * Método que indica si el caracter actual es una cadena
	 * gramática: (")(ε U COS)(")  
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isCadena()
	{	
		int fila = filaActual;
		int col = columnaActual;

		if (!(caracterActual == '"'))
			return false;
		
		String lexema = "";
		int numComillas = 0;
		boolean isCorrect = true;

		// Si hay dos comillas y no se llega a la palabra final se almacena la cadena
		while (numComillas < 2) 
		{
			lexema += caracterActual;

			if (caracterActual == '"')
				numComillas++;
			
			if (caracterActual == EOC) 
			{
				isCorrect = false;
				break;
			}
			
			siguienteCaracter();
		}

		if (isCorrect) 
			almacenarToken(lexema, "str", fila, col);
		else
			almacenarError(lexema, "Desconocido", fila, col);

		return true;
	}

	/**
	 * Método que indica si el caracter actual es un agrupador de apertura
	 * gramática: {
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isAgrupadorInicio()
	{
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == '{') 
		{
			almacenarToken(caracterActual + "", "Inicio Bloque", fila, col);
			siguienteCaracter();
			
			return true;
		}
		return false;
	}

	/**
	 * Método que indica si el caracter actual es un agrupador de cierre
	 * gramática: }
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isAgrupadorFin() 
	{
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == '}') 
		{
			almacenarToken(caracterActual + "", "Fin Bloque", fila, col);
			siguienteCaracter();
			
			return true;
		}
		
		return false;
	}

	/**
	 * Método que indica si el caracter actual es un operador relacional
	 * gramática: (>U<)(ε U=)U(=U!)(=)
	 *
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isOperadorRelacional() 
	{
		String lexema = "";
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == '=') 
		{
			lexema += caracterActual;
			siguienteCaracter();

			if (caracterActual == '=') 
			{
				lexema += caracterActual;
				almacenarToken(lexema, "Igualdad", fila, col);
				siguienteCaracter();
			}
			else
			{
				almacenarError(lexema, "Operador incompleto", fila, col);
			}
			return true;
		} 
		else if (caracterActual == '>') 
		{
			lexema += caracterActual;
			siguienteCaracter();

			if (caracterActual == '=')
			{
				lexema += caracterActual;
				almacenarToken(lexema, "Mayor igual que", fila, col);
				siguienteCaracter();
			}
			else
			{
				almacenarToken(lexema, "Mayor que", fila, col);
			}

			return true;
		} 
		else if (caracterActual == '<') 
		{
			lexema += caracterActual;
			siguienteCaracter();

			if (caracterActual == '=')
			{
				lexema += caracterActual;
				almacenarToken(lexema, "Menor igual que", fila, col);
				siguienteCaracter();
			}
			else 
			{
				almacenarToken(lexema, "Menor que", fila, col);
			}

			return true;
		}
		if (caracterActual == '!') 
		{
			lexema += caracterActual;
			siguienteCaracter();

			if (caracterActual == '=') 
			{
				lexema += caracterActual;
				almacenarToken(lexema, "Diferente de", fila, col);
				siguienteCaracter();
			}
			else 
			{
				almacenarError(lexema, "Operador incompleto", fila, col);
			}
			return true;
		}

		return false;
	}

	/**
	 * Método que indica si el caracter actual es un paréntesis de apertura
	 * gramática: (
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isParentesisInicio() 
	{
		int fila = filaActual;
		int col = columnaActual;
	
		if (caracterActual == '(') 
		{
			almacenarToken(caracterActual + "", "Paréntesis de inicio", fila, col);
			siguienteCaracter();
			
			return true;
		}
		
		return false;
	}

	/**
	 * Método que indica si el caracter actual es una coma
	 * gramática: ,
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isComa()
	{
		int fila = filaActual;
		int col = columnaActual;
	
		if (caracterActual == ',') 
		{
			almacenarToken(caracterActual + "", "Coma", fila, col);
			siguienteCaracter();
		
			return true;
		}
		
		return false;
	}
	
	/**
	 * Método que indica si el caracter actual es un paréntesis de cierre
	 * gramática: )
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isParentesisFin() 
	{	
		int fila = filaActual;
		int col = columnaActual;
		
		if (caracterActual == ')') 
		{
			almacenarToken(caracterActual + "", "Paréntesis de fin", fila, col);
			siguienteCaracter();
		
			return true;
		}		
		
		return false;
	}


	/**
	 * Método que indica si el caracter actual character.
	 * gramática: (')(ε U COS)(')
	 * 
	 * @return true sí lo es, false de lo contrario.
	 */
	public boolean isCaracter()
	{
		int fila = filaActual;
		int col = columnaActual;

		if (!(caracterActual == '\'')) 
			return false;

		String lexema = "";
		int numComillas = 0;
		boolean isCorrect = true;

		while (numComillas < 2) 
		{
			lexema += caracterActual;

			if (caracterActual == '\'') 
				numComillas++;
			
			if (caracterActual == EOC) 
			{
				isCorrect = false;
				break;
			}

			siguienteCaracter();
		}

		if (isCorrect && lexema.length() == 3)
			almacenarToken(lexema, "ch", fila, col);
		else
			almacenarError(lexema, "Desconocido", fila, col);
		return true;
	}

	/**
	 * Indica si el lexema actual es identificador de variable
	 * gramática: (v)(a)(_)(L)(L U D)^*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isIdentificadorVariable()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == 'v')
		{
			lexema+= caracterActual;
			siguienteCaracter();
			
			if(caracterActual == 'a')
			{
				lexema+= caracterActual;
				siguienteCaracter();
				
				if (caracterActual == '_') 
				{
					lexema+= caracterActual;
					siguienteCaracter();
					
					if (caracterActual != EOC && Character.isLetter(caracterActual)) 
					{
						while(Character.isDigit(caracterActual) || Character.isLetter(caracterActual))
						{
							lexema+= caracterActual;
							siguienteCaracter();
						}						
						almacenarToken(lexema, "identificadorVariable", fila, col);
						
						return true;
					}
				}
			}
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Indica si el lexema actual es identificador de variable
	 * gramática: (v)(a)(_)(L)(L U D)^*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isIdentificadorPaquete()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == 'p')
		{
			lexema+= caracterActual;
			siguienteCaracter();
			
			if(caracterActual == 'a')
			{
				lexema+= caracterActual;
				siguienteCaracter();
				
				if (caracterActual == 'c') 
				{
					lexema+= caracterActual;
					siguienteCaracter();
					
					if(caracterActual == 'k')
					{
						lexema+= caracterActual;
						siguienteCaracter();
						
						if(caracterActual == '_')
						{
							lexema+= caracterActual;
							siguienteCaracter();
							
								
							if (caracterActual != EOC && Character.isLetter(caracterActual)) 
							{
								while(Character.isDigit(caracterActual) || Character.isLetter(caracterActual))
								{
									lexema+= caracterActual;
									siguienteCaracter();
								}						
								almacenarToken(lexema, "identificadorPaquete", fila, col);
								
								return true;
							}
						}
					}
						
				}
			}
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Indica si el lexema actual es identificador de metodo
	 * gramática: (m)(t)(_)(L)(L U D)*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isIdentificadorMetodo()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == 'm')
		{
			lexema+= caracterActual;
			siguienteCaracter();
			
			if(caracterActual == 't')
			{
				lexema+= caracterActual;
				siguienteCaracter();
				
				if (caracterActual == '_') 
				{
					lexema+= caracterActual;
					siguienteCaracter();
					
					if (caracterActual != EOC && Character.isLetter(caracterActual)) 
					{
						while(Character.isDigit(caracterActual) || Character.isLetter(caracterActual))
						{
							lexema+= caracterActual;
							siguienteCaracter();
						}						
						almacenarToken(lexema, "identificadorMetodo", fila, col);
						
						return true;
					}
				}
			}
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Metodo que indica si el lexema actual es identificador de clase
	 * gramática: (c)(l)(_)(L)(L U D)*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isIdentificadorClase()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == 'c')
		{
			lexema+= caracterActual;
			siguienteCaracter();
			
			if(caracterActual == 'l')
			{
				lexema+= caracterActual;
				siguienteCaracter();
				
				if (caracterActual == '_') 
				{
					lexema+= caracterActual;
					siguienteCaracter();
					
					if (caracterActual != EOC && Character.isLetter(caracterActual)) 
					{
						while(Character.isDigit(caracterActual) || Character.isLetter(caracterActual))
						{
							lexema+= caracterActual;
							siguienteCaracter();
						}
							
						almacenarToken(lexema, "identificadorClase", fila, col);
						
						return true;
					}
				}
			}
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Metodo que indica si el lexema actual es identificador de atributo
	 * gramática: (a)(t)(_)(L)(L U D)*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isIdentificadorAtributo()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == 'a')
		{
			lexema+= caracterActual;
			siguienteCaracter();
			
			if(caracterActual == 't')
			{
				lexema+= caracterActual;
				siguienteCaracter();
				
				if (caracterActual == '_') 
				{
					lexema+= caracterActual;
					siguienteCaracter();
					
					if (caracterActual != EOC && Character.isLetter(caracterActual)) 
					{
						while( Character.isLetter(caracterActual) || Character.isDigit(caracterActual))
						{
							lexema+= caracterActual;
							siguienteCaracter();
						}
						almacenarToken(lexema, "identificadorAtributo", fila, col);
						
						return true;
					}
				}
			}
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Indica si el caracter actual es operador aditivo
	 * gramática: + U -
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isOperadorAditivo()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == '+' || caracterActual == '-')
		{
			lexema += caracterActual;
			
			if(Character.isDigit(caracterActual))
			{	
				backtracking(backtrack, fila, col);
				return false;
			}
			
			almacenarToken(lexema, "Operador aditivos", fila, col);
			siguienteCaracter();
			return true;
		}
		
		backtracking(backtrack, fila, col);
		return false;
	}
	
	/**
	 * Indica si el caracter actual es operador multiplicativo
	 * gramático: * U /
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isOperadorMultiplicativo()
	{
		backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;
		String lexema = "";
		
		if(caracterActual == '*' || caracterActual == '/')
		{
			lexema += caracterActual;
			
			if(Character.isDigit(caracterActual))
			{	
				backtracking(backtrack, fila, col);
				
				return false;
			}
			
			almacenarToken(lexema, "Operador multiplicativo", fila, col);
			siguienteCaracter();
			
			return true;
		}
		
		backtracking(backtrack, fila, col);
		
		return false;
	}
	
	/**
	 * Indica si el lexema actual es un identificador
	 * gramáticas:
	 * hidden, visible, int, rat, ch, str, bin, true, false, and, or, not, for, while, class
	 * return, nothing, if, ifnot, otherwiseif, otherwise, print
	 * 
	 * @return true si lo es, false de lo congtrario
	 */
	public boolean isPalabraReservada() 
	{
		int backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;

		if (!(Character.isLetter(caracterActual))) {
			return false;
		}

		String lexema = "";

		while (Character.isLetter(caracterActual)
				|| Character.isDigit(caracterActual) || caracterActual == '_') {
			lexema += caracterActual;
			siguienteCaracter();
		}

		if (palabrasReservadas.contains(lexema)) {
			almacenarToken(lexema, "Palabra reservada", fila, col);
		} else {
			backtracking(backtrack, fila, col);
			return false;
		}
		return true;
	}
	
	
	/**
	 * Indica si un identificador no es valido.
	 * 
	 * @return true si lo es, false de lo contrario.
	 */
	public boolean isIdentificadorNoValido() 
	{
		int fila = filaActual;
		int col = columnaActual;

		if (!(Character.isLetter(caracterActual))) {
			return false;
		}

		String lexema = "";

		while (Character.isLetter(caracterActual)
				|| Character.isDigit(caracterActual) || caracterActual == '_') {
			lexema += caracterActual;
			siguienteCaracter();
		}

			almacenarError(lexema, "identificador invalido", fila, col);
		
		return true;
	}
	
	/**
	 * Omite los comentarios de linea
	 * gramático: (#) (cos)*
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isComentarioLinea()
	{	
		if (caracterActual == '#') 
		{
			siguienteCaracter();
		
			while (caracterActual != '\n' && caracterActual != EOC) 
			{
				siguienteCaracter();
			}
			
			return true;
		}
		return false;
	}
	
	/**
	 * Omite los comentarios de bloque
	 * gramático: (=begin ) (cos)* ( =end)
	 * 
	 * @return true si lo es, false de lo contrario
	 */
	public boolean isComentarioBloque()
	{
		int backtrack = posicionActual;
		int fila = filaActual;
		int col = columnaActual;

		String inicio = "=begin";
		String fin = "=end";

		String lexema = "";

		while (Character.isLetter(caracterActual)
				|| Character.isDigit(caracterActual) || caracterActual == '=') {
			lexema += caracterActual;
			siguienteCaracter();
		}
		
		if(lexema.equals(inicio))
			while(!(lexema.equals(fin) || caracterActual == EOC))
			{
				siguienteCaracter();
				lexema = "";
				while (Character.isLetter(caracterActual) || Character.isDigit(caracterActual) || caracterActual == '=') {
					lexema += caracterActual;
					siguienteCaracter();
				}
			}
		if(lexema.equals(fin))
			return true;
		
		backtracking(backtrack, fila, col);
		return false;
	}
	

	//*****************************************************************************
	//								Getters && Setters
	//*****************************************************************************
	
	/**
	 * Metodo que nos retorna el valor de filaActual
	 * @return  filaActual. Valor retornado
	 */
	public int getFilaActual() {
		return filaActual;
	}

	/**
	 * Metodo que permite asignar el valor de filaActual
	 * @param filaActual. Valor a asignar filaActual
	 */
	public void setFilaActual(int filaActual) {
		this.filaActual = filaActual;
	}

	/**
	 * Metodo que nos retorna el valor de columnaActual
	 * @return  columnaActual. Valor retornado
	 */
	public int getColumnaActual() {
		return columnaActual;
	}

	/**
	 * Metodo que permite asignar el valor de columnaActual
	 * @param columnaActual. Valor a asignar columnaActual
	 */
	public void setColumnaActual(int columnaActual) {
		this.columnaActual = columnaActual;
	}

	/**
	 * Metodo que nos retorna el valor de posicionActual
	 * @return  posicionActual. Valor retornado
	 */
	public int getPosicionActual() {
		return posicionActual;
	}

	/**
	 * Metodo que permite asignar el valor de posicionActual
	 * @param posicionActual. Valor a asignar posicionActual
	 */
	public void setPosicionActual(int posicionActual) {
		this.posicionActual = posicionActual;
	}

	/**
	 * Metodo que nos retorna el valor de caracterActual
	 * @return  caracterActual. Valor retornado
	 */
	public char getCaracterActual() {
		return caracterActual;
	}

	/**
	 * Metodo que permite asignar el valor de caracterActual
	 * @param caracterActual. Valor a asignar caracterActual
	 */
	public void setCaracterActual(char caracterActual) {
		this.caracterActual = caracterActual;
	}

	/**
	 * Metodo que nos retorna el valor de codigoFuente
	 * @return  codigoFuente. Valor retornado
	 */
	public String getCodigoFuente() {
		return codigoFuente;
	}

	/**
	 * Metodo que permite asignar el valor de codigoFuente
	 * @param codigoFuente. Valor a asignar codigoFuente
	 */
	public void setCodigoFuente(String codigoFuente) {
		this.codigoFuente = codigoFuente;
	}

	/**
	 * Metodo que nos retorna el valor de eoc
	 * @return  eoc. Valor retornado
	 */
	public static char getEoc() {
		return EOC;
	}

	/**
	 * Metodo que permite asignar el valor de eoc
	 * @param eoc. Valor a asignar eoc
	 */
	public static void setEoc(char eoc) {
		EOC = eoc;
	}

	/**
	 * Metodo que nos retorna el valor de tablaSimbolos
	 * @return  tablaSimbolos. Valor retornado
	 */
	public ArrayList<SimboloLexico> getTablaSimbolos() {
		return tablaSimbolos;
	}

	/**
	 * Metodo que permite asignar el valor de tablaSimbolos
	 * @param tablaSimbolos. Valor a asignar tablaSimbolos
	 */
	public void setTablaSimbolos(ArrayList<SimboloLexico> tablaSimbolos) {
		this.tablaSimbolos = tablaSimbolos;
	}

	/**
	 * Metodo que nos retorna el valor de tablaErrores
	 * @return  tablaErrores. Valor retornado
	 */
	public ArrayList<SimboloLexico> getTablaErrores() {
		return tablaErrores;
	}

	/**
	 * Metodo que permite asignar el valor de tablaErrores
	 * @param tablaErrores. Valor a asignar tablaErrores
	 */
	public void setTablaErrores(ArrayList<SimboloLexico> tablaErrores) {
		this.tablaErrores = tablaErrores;
	}

	/**
	 * Metodo que nos retorna el valor de palabrasReservadas
	 * @return  palabrasReservadas. Valor retornado
	 */
	public ArrayList<String> getPalabrasReservadas() {
		return palabrasReservadas;
	}

	/**
	 * Metodo que permite asignar el valor de palabrasReservadas
	 * @param palabrasReservadas. Valor a asignar palabrasReservadas
	 */
	public void setPalabrasReservadas(ArrayList<String> palabrasReservadas) {
		this.palabrasReservadas = palabrasReservadas;
	}

	/**
	 * Metodo que nos retorna el valor de rutaPalabrasReservadas
	 * @return  rutaPalabrasReservadas. Valor retornado
	 */
	public static String getRutaPalabrasReservadas() {
		return rutaPalabrasReservadas;
	}

	/**
	 * Metodo que permite asignar el valor de rutaPalabrasReservadas
	 * @param rutaPalabrasReservadas. Valor a asignar rutaPalabrasReservadas
	 */
	public static void setRutaPalabrasReservadas(String rutaPalabrasReservadas) {
		AnalizadorLexico.rutaPalabrasReservadas = rutaPalabrasReservadas;
	}

	/**
	 * Metodo que nos retorna el valor de backtrack
	 * @return  backtrack. Valor retornado
	 */
	public int getBacktrack() {
		return backtrack;
	}

	/**
	 * Metodo que permite asignar el valor de backtrack
	 * @param backtrack. Valor a asignar backtrack
	 */
	public void setBacktrack(int backtrack) {
		this.backtrack = backtrack;
	}

}
